本文基于 Android10
源码环境
Android 源码中提供了一系列的 C++ 类(libbinder 库)来简化 Binder 驱动的使用。使得开发者能快速在 Android 系统源码中添加 Binder 服务和使用 Binder 服务。接下来我们使用 Android 源码中提供的辅助类和 C++ 语言来编写一个 Binder C++ 示例程序。
可以在这里 (opens new window)下载到示例程序。
使用 C++ 实现一个 Binder 服务分为以下几步:
- 定义协议
- 实现服务端协议
- 实现客户端协议
- 服务端程序实现
- 客户端程序实现
# 1. 定义通信协议
通信协议由三部分组成:
- 通信协议接口
- 通信协议服务端实现
- 通信协议客户端实现
接下来我们来实现通信协议接口 IHelloService, 接口继承自 IInterface,描述了名为 Hello 的 Binder 服务对外提供的功能。
//IHelloService.h 类名的起始字母需要是大写的 I
class IHelloService: public IInterface {
public:
//DECLARE_META_INTERFACE 是一个宏,声明了一些变量和函数
DECLARE_META_INTERFACE(HelloService);
//Binder 服务对外提供的功能
virtual void sayHello() = 0;
virtual int sayHelloTo(const char *name) = 0;
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 2. 通信协议服务端实现
通信协议服务端实现是一个继承自 BnInterface<IHelloService>
的类:
//声明
//IHelloService.h
class BnHelloService: public BnInterface<IHelloService> {
public:
//服务端收到数据后的回调
status_t onTransact(uint32_t code, const Parcefl& data, Parcel* reply, uint32_t lags = 0);
void sayHello();
int sayHelloTo(const char *name);
};
//实现
//BnHelloService.cpp
#define LOG_TAG "HelloService"
#include <log/log.h>
#include "IHelloService.h"
//服务端收到数据的回调
status_t BnHelloService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
//code 表示客户端需要调用哪个函数
switch(code) {
//调用 sayhello
case HELLO_SVR_CMD_SAYHELLO: {
//调用 sayhello 函数
sayHello();
//写入回复给客户端的数据
reply->writeInt32(0);
return NO_ERROR;
} break;
//调用 sayhelloto
case HELLO_SVR_CMD_SAYHELLO_TO: {
//取出客户端发送的参数
int32_t policy = data.readInt32();
String16 name16_tmp = data.readString16();
String16 name16 = data.readString16();
String8 name8(name16);
//调用 sayHelloTo 函数
int cnt = sayHelloTo(name8.string());
//写入回复给客户端的数据
reply->writeInt32(0);
reply->writeInt32(cnt);
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
}
//服务端函数的具体实现
void BnHelloService::sayHello() {
static int count = 0;
ALOGI("say hello :%d\n ", ++count);
}
int BnHelloService::sayHelloTo(const char *name) {
static int cnt = 0;
ALOGI("say hello to %s : %d\n", name, ++cnt);
return cnt;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
为叙述方便我们称 BnHelloService 以及同类型的类为 Binder 服务类
# 3. 通信协议客户端协议实现
客户端协议实现是一个继承自 BpInterface<IHelloService>
的类
//客户端
//IHelloService.h
class BpHelloService: public BpInterface<IHelloService> {
public:
BpHelloService(const sp<IBinder>& impl);
void sayHello();
int sayHelloTo(const char *name);
};
//BpHelloService.cpp
#include "IHelloService.h"
//调用父类构造函数
BpHelloService::BpHelloService(const sp<IBinder>& impl):BpInterface<IHelloService>(impl) {
}
void BpHelloService::sayHello() {
Parcel data, reply;
data.writeInt32(0);
data.writeString16(String16("IHelloService"));
//发起远程调用
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
int BpHelloService::sayHelloTo(const char *name) {
Parcel data, reply;
int exception;
data.writeInt32(0);
data.writeString16(String16("IHelloService"));
data.writeString16(String16(name));
//发起远程调用
remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
exception = reply.readInt32();
if (exception)
return -1;
else
return reply.readInt32();
}
IMPLEMENT_META_INTERFACE(HelloService, "IHelloService");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
为叙述方便我们称 BpHelloService 以及同类型的类为 Binder 代理类
# 4. 服务端程序实现
int main(int argc, char const *argv[])
{
//使用 ProcessState 类完成 binder 驱动的初始化
sp<ProcessState> proc(ProcessState::self());
//注册服务
sp<IServiceManager> sm = defaultServiceManager();
sm->addService(String16("hello"), new BnHelloService());
//开启 binder 线程池
ProcessState::self()->startThreadPool();
//加入线程池
IPCThreadState::self()->joinThreadPool();
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 5. 客户端程序实现
int main(int argc, char const *argv[])
{
//使用 ProcessState 类完成 binder 驱动的初始化
sp<ProcessState> proc(ProcessState::self());
//获取 hello 服务
sp<IServiceManager> sm = defaultServiceManager();
//返回的是 BpBinder 指针
sp<IBinder> binder = sm->getService(String16("hello"));
sp<IHelloService> service = interface_cast<IHelloService>(binder);
if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}
//发起远程调用
service->sayHello();
int cnt = service->sayHelloTo("nihao");
ALOGI("client call sayhello_to, cnt = %d", cnt);
return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 6. 编译运行
项目根目录下添加 Android.bp
:
cc_binary {
name: "MyCppBinderServer",
srcs: ["BinderServer.cpp", "BnHelloService.cpp","BpHelloService.cpp"],
shared_libs: [
"liblog",
"libcutils",
"libutils",
"libbinder",
],
}
cc_binary {
name: "MyCppBinderClient",
srcs: ["BinderClient.cpp", "BpHelloService.cpp"],
shared_libs: [
"liblog",
"libcutils",
"libutils",
"libbinder",
],
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
将项目放到 aosp 任意目录下,然后执行以下命令:
source build/envsetup.sh
lunch aosp_x86_64-eng
#启动模拟器
emulator
1
2
3
4
2
3
4
进入到项目目录 device/jelly/rice14/BinderCppDemo
,然后执行单编命令:
mm
1
编译完成后,将程序上传到模拟器并执行。
传输可执行文件到模拟器:
adb push out/target/product/generic_x86_64/symbols/system/bin/MyCppBinderServer /data/local/tmp
adb push out/target/product/generic_x86_64/symbols/system/bin/MyCppBinderClient /data/local/tmp
1
2
3
4
2
3
4
接下来 adb shell
进入模拟器 shell
环境:
adb shell
cd /data/local/tmp
./MyCppBinderServer
# 从新开一个终端进入 adb shell
cd /data/local/tmp
./MyCppBinderClient
1
2
3
4
5
6
2
3
4
5
6
最后通过 logcat 查看执行结果: